home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
-
- Arbitrary Precision Math Library General Public License
- (Written October 5, 1988)
-
- Copyright (C) 1988 Lloyd Zusman, Master Byte Software, Los
- Gatos, California. Everyone is permitted to copy and distribute
- verbatim copies of this license, but changing it is not allowed.
- You can also use this wording to make the terms for other programs.
-
- The wording of this license is based on that of the
- "GNU EMACS GENERAL PUBLIC LICENSE" by Richard Stallman,
- Copyright (C) 1985, 1987, 1988, version of February 11, 1988,
- but since some of the text has been changed, please be sure to
- READ THIS CAREFULLY!
-
- This general public license is intended to give everyone the right
- to share the Arbitrary Precision Math Library (hereinafter referred to
- as the "APM Library"). To make sure that you get the rights we want
- you to have, I need to make restrictions that forbid anyone to deny
- you these rights or to ask you to surrender the rights.
-
- Specifically, we want to make sure that you have the right to give
- away copies of the APM Library, that you receive source code or else
- can get it if you want it, that you can change the APM Library or use
- pieces of it in new programs, and that you know you can do these
- things.
-
- To make sure that everyone has such rights, we have to forbid you to
- deprive anyone else of these rights. For example, if you distribute
- copies of the APM Library, you must give the recipients all the
- rights that you have. You must make sure that they, too, receive or
- can get the source code. And you must tell them their rights.
-
- Also, for our own protection, we must make certain that everyone
- finds out that there is no warranty for the APM Library. If the APM
- Library is modified by someone else and passed on, we want its
- recipients to know that what they have is not what we distributed, so
- that any problems introduced by others will not reflect on our
- reputation.
-
- Therefore we (Lloyd Zusman and Master Byte Software) make the
- following terms which say what you must do to be allowed to
- distribute or change the APM Library.
-
- COPYING POLICIES
-
- 1. You may copy and distribute verbatim copies of the APM Library
- source code as you receive it, in any medium, provided that you
- conspicuously and appropriately publish on each copy a valid copyright
- notice "Copyright (C) 1988 Lloyd Zusman, Master Byte Software, Los
- Gatos, California" (or with whatever year is appropriate); keep intact
- the notices on all files that refer to this License Agreement and to
- the absence of any warranty; and give any other recipients of the the
- APM Library program a copy of this License Agreement along with the
- program. You may charge a distribution fee for the physical act of
- transferring a copy.
-
- 2. You may modify your copy or copies of the APM Library source code or
- any portion of it, and copy and distribute such modifications under
- the terms of Paragraph 1 above, provided that you also do the following:
-
- a) cause the modified files to carry prominent notices stating
- that you changed the files and the date of any change; and
-
- b) cause the whole of any work that you distribute or publish, that in
- whole or in part contains or is a derivative of the APM Library or any
- part thereof, to be licensed to all third parties on terms identical
- to those contained in this License Agreement (except that you may
- choose to grant more extensive warranty protection to some or all
- third parties, at your option).
-
- c) You may charge a distribution fee for the physical act of
- transferring a copy, and you may at your option offer warranty
- protection in exchange for a fee.
-
- d) You may not charge a license fee for the whole of any work that
- you distribute or publish, that in whole or in part contains or is
- a derivative of the APM library or any part thereof, without the
- express written permission of Lloyd Zusman and Master Byte Software;
- whether this permission is granted for free or in return for goods
- services, royalties, or other compensation will be determined
- solely by Lloyd Zusman and Master Byte Software.
-
- Mere aggregation of another unrelated program with this program (or its
- derivative) on a volume of a storage or distribution medium does not bring
- the other program under the scope of these terms.
-
- 3. You may copy and distribute the APM Library (or a portion or
- derivative of it, under Paragraph 2) in object code or executable form
- under all the terms of Paragraphs 1 and 2 above provided that you also
- do one of the following:
-
- a) accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of
- Paragraphs 1 and 2 above; or,
-
- b) accompany it with a written offer, valid for at least three
- years, to give any third party free (except for a nominal
- shipping charge) a complete machine-readable copy of the
- corresponding source code, to be distributed under the terms of
- Paragraphs 1 and 2 above; or,
-
- c) accompany it with the information you received as to where the
- corresponding source code may be obtained. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form alone.)
-
- For an executable file, complete source code means all the source code
- for all modules it contains; but, as a special exception, it need not
- include source code for modules which are standard libraries that
- accompany the operating system on which the executable file runs.
-
- 4. You may not copy, sublicense, distribute or transfer the APM
- Library except as expressly provided under this License Agreement.
- Any attempt otherwise to copy, sublicense, distribute or transfer the
- APM Library is void and your rights to use the APM Library under this
- License agreement shall be automatically terminated. However, parties
- who have received computer software programs from you with this
- License Agreement will not have their licenses terminated so long as
- such parties remain in full compliance.
-
- 5. If you wish to incorporate parts of the APM Library into other
- programs whose distribution conditions are different, write to Lloyd
- Zusman at Master Byte Software. We have not yet worked out a simple
- rule that can be stated here, but we will often permit this. We will
- be guided by the goals of (1) preserving the free status of all
- derivatives of our free software; of (2) promoting the sharing and
- reuse of software; and of (3) not allowing anyone to profit from the
- use of our software without us also having the opportunity to share
- in these profits.
-
- Your comments and suggestions about our licensing policies and our
- software are welcome! Please contact Lloyd Zusman, Master Byte
- Software, 127 Wilder Ave., Los Gatos, California 95030, or call
- (408) 395-5693.
-
- NO WARRANTY
-
- BECAUSE THE APM LIBRARY IS LICENSED FREE OF CHARGE, WE PROVIDE
- ABSOLUTELY NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE
- LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING, MASTER BYTE SOFTWARE,
- LLOYD ZUSMAN AND/OR OTHER PARTIES PROVIDE THE APM LIBRARY "AS IS"
- WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
- BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
- AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE THE APM
- LIBRARY PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
- SERVICING, REPAIR OR CORRECTION.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL MASTER BYTE
- SOFTWARE, LLOYD ZUSMAN, AND/OR ANY OTHER PARTY WHO MAY MODIFY AND
- REDISTRIBUTE THE APM LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
- DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL,
- INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
- INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
- BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A
- FAILURE OF THE PROGRAM TO OPERATE WITH PROGRAMS NOT DISTRIBUTED BY
- MASTER BYTE SOFTWARE) THE PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF
- THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
-
- ******************************************************************************/
-
-
- /*
- * Calculator mode for the APM library.
- *
- * $Log: calc.c,v $
- * Revision 1.0 88/10/05 12:38:11 ljz
- * Initial release.
- *
- */
- #ifndef lint
- static char rcsid[] = "$Header: calc.c,v 1.0 88/10/05 12:38:11 ljz Exp $";
- #endif /* ! lint */
-
- #include <stdio.h>
- #include <varargs.h>
- #include "apm.h"
- #include "apmlocal.h"
-
- /*
- * The stack is declared to contain one more value than is used so that
- * the calculation of &APM_stack[APM_STACK_SIZE] doesn't generate an
- * error (I have been led to believe that under certain machine
- * architectures, calculating an invalid pointer will cause an error
- * even if the pointer is not dereferenced).
- */
- static APM APM_stack[APM_STACK_SIZE + 1];
- static APM *APM_stack_ptr = (APM *)NULL;
-
- /*
- * We need a few scratch registers. The user can't get to them, but
- * I use them in some of these routines.
- */
- #define NUM_SCRATCH 3
- #define TOT_REGISTERS (APM_NUM_REGISTERS + NUM_SCRATCH)
- static APM APM_register[TOT_REGISTERS];
-
- /*
- * This macro is used to access the scratch registers.
- */
- #define XREG(N) APM_register[APM_NUM_REGISTERS + (N)]
-
- static int
- APM_get_reg(value, regnum)
- APM value;
- int regnum;
- {
- APM reg;
- int ercode = APM_OK;
-
- APM_calc_init();
-
- apm_errno = APM_OK;
-
- if (regnum < 0 || regnum >= APM_NUM_REGISTERS) {
- return (APM_set_errno(APM_EPARM));
- }
-
- reg = APM_register[regnum];
- ercode = APM_size(value, reg->length);
- if (ercode < APM_OK) {
- return (APM_set_errno(ercode));
- }
-
- APM_copy_bytes(value->data, reg->data, reg->length * sizeof(short));
- value->sign = SIGNOF(reg->sign);
- value->base = reg->base;
- value->length = reg->length;
- value->dp = reg->dp;
- return (APM_OK);
- }
-
- static int
- APM_set_reg(previous, regnum, value)
- APM previous;
- int regnum;
- APM value;
- {
- APM reg;
- int ercode = APM_OK;
-
- APM_calc_init();
-
- apm_errno = APM_OK;
-
- if (regnum < 0 || regnum >= APM_NUM_REGISTERS) {
- return (APM_set_errno(APM_EPARM));
- }
-
-
- ercode = apm_validate(value);
- if (ercode < APM_OK) {
- return (APM_set_errno(ercode));
- }
-
- if (previous == value) {
- return (APM_set_errno(APM_EOVERLAP));
- }
-
- ercode = APM_get_reg(previous, regnum);
- if (ercode < APM_OK) {
- return (APM_set_errno(ercode));
- }
-
- reg = APM_register[regnum];
- ercode = APM_size(reg, value->length);
- if (ercode < APM_OK) {
- return (APM_set_errno(ercode));
- }
-
- APM_copy_bytes(reg->data, value->data, value->length * sizeof(short));
- reg->sign = SIGNOF(value->sign);
- reg->base = value->base;
- reg->length = value->length;
- reg->dp = value->dp;
- return (APM_OK);
- }
-
- static int
- APM_calc_op(value)
- APM value;
- {
- int ercode = APM_OK;
-
- APM_calc_init();
-
- if (value == (APM)NULL) {
- return (APM_ENULL);
- }
- else if (value->magic != OP_MAGIC) {
- return (APM_EBADVAL);
- }
-
- switch (value->length) { /* length = command, dp = operand */
- case APM_CALC_ABS: /* unary operations */
- case APM_CALC_NEG:
- case APM_CALC_RECIP:
- case APM_CALC_SCALE:
- ercode = APM_calc_unop(value->length, value->dp);
- break;
- case APM_CALC_ADD: /* binary operations */
- case APM_CALC_SUB:
- case APM_CALC_MUL:
- case APM_CALC_DIV:
- ercode = APM_calc_binop(value->length, value->dp);
- break;
- case APM_CALC_CLEAR: /* miscellaneous operations */
- case APM_CALC_DUP:
- case APM_CALC_SWAP:
- case APM_CALC_PUSH:
- case APM_CALC_POP:
- ercode = APM_calc_misc(value->length, value->dp);
- break;
- default:
- ercode = APM_EBADVAL;
- break;
- }
-
- return (ercode);
- }
-
- static int
- APM_calc_unop(operation, operand)
- int operation;
- int operand;
- {
- int ercode = APM_OK;
-
- APM_calc_init();
-
- switch (operation) {
- case APM_CALC_ABS:
- ercode = APM_pop(XREG(0));
- if (ercode != APM_OK) {
- break;
- }
- ercode = apm_absolute_value(XREG(1), XREG(0));
- if (ercode < APM_OK) {
- APM_push(XREG(0));
- }
- else {
- ercode = APM_push(XREG(1));
- }
- break;
- case APM_CALC_NEG:
- ercode = APM_pop(XREG(0));
- if (ercode != APM_OK) {
- break;
- }
- ercode = apm_negate(XREG(1), XREG(0));
- if (ercode < APM_OK) {
- APM_push(XREG(0));
- }
- else {
- ercode = APM_push(XREG(1));
- }
- break;
- case APM_CALC_RECIP:
- ercode = APM_pop(XREG(0));
- if (ercode != APM_OK) {
- break;
- }
- ercode = apm_reciprocal(XREG(1), operand, XREG(0));
- if (ercode < APM_OK) {
- APM_push(XREG(0));
- }
- else {
- ercode = APM_push(XREG(1));
- }
- break;
- case APM_CALC_SCALE:
- ercode = APM_pop(XREG(0));
- if (ercode != APM_OK) {
- break;
- }
- ercode = apm_scale(XREG(1), XREG(0), operand);
- if (ercode < APM_OK) {
- APM_push(XREG(0));
- }
- else {
- ercode = APM_push(XREG(1));
- }
- break;
- default:
- ercode = APM_EBADVAL;
- break;
- }
-
- return (APM_set_errno(ercode));
- }
-
- static int
- APM_calc_binop(operation, operand)
- int operation;
- int operand;
- {
- int ercode = APM_OK;
-
- APM_calc_init();
-
- switch (operation) {
- case APM_CALC_ADD:
- APM_pop(XREG(0));
- APM_pop(XREG(1));
- apm_assign_long(XREG(2), 0L, 0, 0);
- ercode = apm_add(XREG(2), XREG(1), XREG(0));
- APM_push(XREG(2));
- break;
- case APM_CALC_SUB:
- APM_pop(XREG(0));
- APM_pop(XREG(1));
- apm_assign_long(XREG(2), 0L, 0, 0);
- ercode = apm_subtract(XREG(2), XREG(1), XREG(0));
- APM_push(XREG(2));
- break;
- case APM_CALC_MUL:
- APM_pop(XREG(0));
- APM_pop(XREG(1));
- apm_assign_long(XREG(2), 0L, 0, 0);
- ercode = apm_multiply(XREG(2), XREG(1), XREG(0));
- APM_push(XREG(2));
- break;
- case APM_CALC_DIV:
- APM_pop(XREG(0));
- APM_pop(XREG(1));
- apm_assign_long(XREG(2), 0L, 0, 0);
- ercode = apm_divide(XREG(2), operand, APM_register[0],
- XREG(1), XREG(0));
- APM_push(XREG(2));
- break;
- default:
- ercode = APM_EBADVAL;
- break;
- }
-
- return (APM_set_errno(ercode));
- }
-
- static int
- APM_calc_misc(operation, operand)
- int operation;
- int operand;
- {
- int ercode = APM_OK;
-
- APM_calc_init();
-
- switch (operation) {
- case APM_CALC_CLEAR:
- APM_stack_ptr = &APM_stack[0];
- break;
- case APM_CALC_DUP:
- if ((ercode = APM_pop(XREG(0))) == APM_OK) {
- if ((ercode = APM_push(XREG(0))) == APM_OK) {
- ercode = APM_push(XREG(0));
- }
- }
- break;
- case APM_CALC_SWAP:
- if ((ercode = APM_pop(XREG(0))) == APM_OK) {
- if ((ercode = APM_pop(XREG(1))) == APM_OK) {
- if ((ercode = APM_push(XREG(0))) == APM_OK) {
- ercode = APM_push(XREG(1));
- }
- }
- }
- break;
- case APM_CALC_PUSH:
- if (operand < 0 || operand >= APM_NUM_REGISTERS) {
- ercode = APM_EPARM;
- break;
- }
- ercode = APM_push(APM_register[operand]);
- break;
- case APM_CALC_POP:
- if (operand < 0 || operand >= APM_NUM_REGISTERS) {
- ercode = APM_EPARM;
- break;
- }
- ercode = APM_pop(APM_register[operand]);
- break;
- default:
- ercode = APM_EBADVAL;
- break;
- }
-
- return (APM_set_errno(ercode));
- }
-
- static int
- APM_push(value)
- APM value;
- {
- int i;
- int ercode = APM_OK;
-
- APM_calc_init();
-
- /*
- * If stack is full, shift everything down by one, thereby losing
- * the value at the bottom of the stack.
- */
- if (APM_stack_ptr >= &APM_stack[APM_STACK_SIZE]) {
- for (i = 0; i < APM_STACK_SIZE - 1; ++i) {
- (void)apm_assign(APM_stack[i], APM_stack[i + 1]);
- }
- APM_stack_ptr = &APM_stack[APM_STACK_SIZE - 1];
- }
-
- ercode = apm_assign(*APM_stack_ptr, value);
- if (ercode >= APM_OK) {
- ++APM_stack_ptr;
- }
-
- return (ercode);
- }
-
- static int
- APM_pop(value)
- APM value;
- {
- int ercode = APM_OK;
-
- APM_calc_init();
-
- if (APM_stack_ptr <= &APM_stack[0]) { /* at bottom of stack */
- ercode = apm_assign_long(value, 0L, 0, 0);
- if (ercode >= APM_OK) {
- APM_stack_ptr = &APM_stack[0]; /* just in case */
- }
- }
- else {
- ercode = apm_assign(value, APM_stack_ptr[-1]);
- if (ercode >= APM_OK) {
- --APM_stack_ptr;
- }
- }
-
- return (ercode);
- }
-
- int
- apm_get_register(value, regnum)
- APM value;
- int regnum;
- {
- APM reg;
-
- apm_errno = APM_OK;
-
- APM_calc_init();
-
- if (regnum < 0 || regnum >= APM_NUM_REGISTERS) {
- return (APM_error(APM_EPARM));
- }
-
- ERR_RETURN(APM_get_reg(value, regnum));
-
- return (APM_OK);
- }
-
- int
- apm_set_register(previous, regnum, value)
- APM previous;
- int regnum;
- APM value;
- {
- APM reg;
-
- apm_errno = APM_OK;
-
- APM_calc_init();
-
- if (regnum < 0 || regnum >= APM_NUM_REGISTERS) {
- return (APM_error(APM_EPARM));
- }
-
- ERR_RETURN(APM_set_reg(previous, regnum, value));
-
- return (APM_OK);
- }
-
- int
- apm_calc(va_alist)
- va_dcl
- {
- va_list ap;
- APM result;
- APM value;
-
- va_start(ap);
-
- apm_errno = APM_OK;
-
- result = va_arg(ap, APM);
- ERR_RETURN(APM_val_format(result));
-
- APM_calc_init();
-
- APM_calc_misc(APM_CALC_CLEAR, 0); /* start with a clear stack */
-
- while ((value = va_arg(ap, APM)) != NULL) {
- if (value->magic == APM_MAGIC) {
- ERR_RETURN(APM_push(value));
- }
- else if (value->magic == OP_MAGIC) {
- int ercode = APM_calc_op(value);
- (void)APM_free(value); /* we must free operations */
- ERR_RETURN(ercode);
- }
- else {
- return (APM_set_errno(APM_EBADVAL));
- }
- }
-
- #ifdef MSDOS
- va_end(ap);
- #else
- va_end();
- #endif /* MSDOS */
-
- return (APM_pop(result));
- }
-
- APM
- apm_op_alloc(type, operand)
- int type;
- int operand;
- {
- APM op;
-
- apm_errno = APM_OK;
-
- op = APM_alloc();
- if (op == (APM)NULL) {
- APM_set_errno(APM_ENOMEM);
- return ((APM)NULL);
- }
- op->magic = OP_MAGIC;
- op->length = type;
- op->dp = operand;
-
- return (op);
- }
-
- void
- APM_calc_init()
- {
- if (APM_stack_ptr == (APM *)NULL) {
- APM local;
- int ercode = APM_OK;
- int i;
-
- for (i = 0; i < TOT_REGISTERS; ++i) {
- local = APM_alloc();
- if (local == (APM)NULL) {
- APM_set_errno(APM_ENOMEM);
- break;
- }
- ercode = APM_parse_long(local, 0L, 0);
- if (ercode < APM_OK) {
- APM_set_errno(ercode);
- break;
- }
- APM_register[i] = local;
- }
- for (i = 0; i < APM_STACK_SIZE; ++i) {
- local = APM_alloc();
- if (local == (APM)NULL) {
- APM_set_errno(APM_ENOMEM);
- break;
- }
- ercode = APM_parse_long(local, 0L, 0);
- if (ercode < APM_OK) {
- APM_set_errno(ercode);
- break;
- }
- APM_stack[i] = local;
- }
- APM_stack_ptr = &APM_stack[0];
- }
- }
-